package com.scl.reminder

import android.annotation.SuppressLint
import android.content.ContentUris
import android.content.ContentValues
import android.content.Context
import android.graphics.Color
import android.net.Uri
import android.provider.CalendarContract
import android.util.Log
import java.io.IOException
import java.util.*

/**
 * Created by admin on 2021/10/12.
 * name:
 */
object CalendarReminder {

    //日历用户的URL
    private const val CALENDER_URL = "content://com.android.calendar/calendars"

    //事件的URL
    private const val CALENDER_EVENT_URL = "content://com.android.calendar/events"

    //事件提醒的URL
    private const val CALENDER_REMINDER_URL = "content://com.android.calendar/reminders"

    /*账户信息*/
    private const val CALENDARS_NAME = "喝水鱼"
    private const val CALENDARS_ACCOUNT_NAME = "喝水鱼@gmail.com"
    private const val CALENDARS_ACCOUNT_TYPE = "com.android.exchange"
    private const val CALENDARS_DISPLAY_NAME = "喝水鱼"

    private const val SITE_SIGN = "自定义事件"

    /**
     * 检查是否已经添加了日历账户，如果没有添加先添加一个日历账户再查询
     * 获取账户成功返回账户id，否则返回-1
     */
    private fun checkAndAddCalendarAccount(context: Context): Int {
        val oldId = checkCalendarAccount(context)

        return if (oldId >= 0) {
            oldId
        } else {
            val addId = addCalendarAccount(context)
            if (addId >= 0) {
                checkCalendarAccount(context)
            } else {
                -1
            }
        }
    }

    /**
     * 检查是否存在现有账户，存在则返回账户id，否则返回-1
     */
    @SuppressLint("Range")
    private fun checkCalendarAccount(context: Context): Int {
        val userCursor = context.contentResolver.query(
            Uri.parse(CALENDER_URL),
            null, null, null, null
        ) ?: return -1
        userCursor.use {
            val count = it.count
            return if (count > 0) {
                it.moveToFirst()
                it.getInt(it.getColumnIndex(CalendarContract.Calendars._ID))
            } else {
                -1
            }
        }
    }

    /**
     * 添加日历账户，账户创建成功则返回账户id，否则返回-1
     */
    private fun addCalendarAccount(context: Context): Long {
        val value = ContentValues()
        //日历的名称
        value.put(CalendarContract.Calendars.NAME, CALENDARS_NAME)
        //设备上的帐户
        value.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
        //设备类型
        value.put(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
        //日历的显示名称。列名。
        value.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME)

        value.put(CalendarContract.Calendars.VISIBLE, 1)
        value.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.BLUE)
        value.put(
            CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL,
            CalendarContract.Calendars.CAL_ACCESS_OWNER
        )
        value.put(CalendarContract.Calendars.SYNC_EVENTS, 1)
        value.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, TimeZone.getDefault().id)
        value.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDARS_ACCOUNT_NAME)
        value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0)

        val calendarUri = Uri.parse(CALENDER_URL).buildUpon()
            .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true")
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME)
            .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE)
            .build()

        val result = context.contentResolver.insert(calendarUri, value)
        return if (result == null) -1 else ContentUris.parseId(result)
    }

    /**
     * 写入事件到日历
     *
     * @param title 标题
     *
     * @param reminderTime 时间
     *
     * @param reminderType 添加事件重复类型  ReminderType.TYPE_NUMBER 按次 如果是这个参数  需要传入number
     *                                   ReminderType.TYPE_EVER 永久  不需要传入number
     * @param number 提醒次数 默认1次 ReminderType.TYPE_NUMBER 类型时才需要
     *
     * @param site_sign 地点
     *
     * @param description 事件描述
     *
     * @param weekendReminder : 周末是否提醒  默认提醒
     */
    private fun addCalendarEvent(
        context: Context, title: String, reminderTime: Long,
        site_sign: String, description: String,
        reminderType: TypeStatus, number: Int,
        weekendReminder: Boolean = true
    ) {
        //获取日历id
        val calId = checkAndAddCalendarAccount(context)
        if (calId < 0) {
            return
        }

        //添加事件
        val mCalendar = Calendar.getInstance()
        //设置时间
        mCalendar.timeInMillis = reminderTime
        val time = mCalendar.time.time

        val event = ContentValues()
        event.put("title", title)
        event.put("description", description)
        event.put("calendar_id", calId)
        event.put("eventLocation", site_sign)
        event.put(CalendarContract.Events.DTSTART, time)
        /*添加重复要加这个 p0s 不然不重复*/
        event.put(CalendarContract.Events.DURATION, "P0S")
        /*设置闹钟提醒， 不起作用 需要手动去开启*/
        event.put(CalendarContract.Events.HAS_ALARM, 1)
        /*重复规则*/
        when (reminderType) {
            TypeStatus.EVER -> {  //永久
                if (weekendReminder) {
                    event.put(
                        CalendarContract.Events.RRULE,
                        "FREQ=WEEKLY;INTERVAL=1;WKST=SU;BYDAY=MO,TU,WE,TH,FR,SA,SU"
                    )
                } else {
                    event.put(
                        CalendarContract.Events.RRULE,
                        "FREQ=WEEKLY;INTERVAL=1;WKST=SU;BYDAY=MO,TU,WE,TH,FR"
                    )
                }

            }
            TypeStatus.NUMBER -> { //按次写入
                if (weekendReminder) {
                    event.put(CalendarContract.Events.RRULE, "FREQ=DAILY;COUNT=$number")
                } else {
                    event.put(
                        CalendarContract.Events.RRULE,
                        "FREQ=DAILY;INTERVAL=1;WKST=SU;BYDAY=MO,TU,WE,TH,FR;COUNT=$number"
                    )
                }

            }
        }
        /*时区*/
        event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().id)
        val newEvent =
            context.contentResolver.insert(Uri.parse(CALENDER_EVENT_URL), event) ?: return

        /*事件提醒的设定*/
        val values = ContentValues()
        values.put(CalendarContract.Reminders.EVENT_ID, ContentUris.parseId(newEvent))
        values.put(CalendarContract.Reminders.MINUTES, 0) //提前多久提醒
        values.put(CalendarContract.Reminders.METHOD, 1)
        val uri = context.contentResolver.insert(Uri.parse(CALENDER_REMINDER_URL), values) ?: return
    }

    /**
     * 删除日历事件
     *
     * @param site_sign 传入的 要和 添加事件字段保持一致 不然无法删除
     */
    @SuppressLint("Range")
    fun deleteCalendarEvent(context: Context, site_sign: String = SITE_SIGN) {
        val eventCursor = context.contentResolver.query(
            Uri.parse(CALENDER_EVENT_URL),
            null, null, null, null
        )

        eventCursor?.run {
            if (this.count > 0) {
                //遍历所有事件，找到title跟需要查询的title一样的项
                this.moveToFirst()
                while (!this.isAfterLast) {
                    val eventTitle: String = this.getString(this.getColumnIndex("eventLocation"))
                    if (site_sign == eventTitle) {
                        val id: Int =
                            this.getInt(this.getColumnIndex(CalendarContract.Calendars._ID)) //取得id
                        val deleteUri: Uri =
                            ContentUris.withAppendedId(Uri.parse(CALENDER_EVENT_URL), id.toLong())
                        val rows: Int = context.contentResolver.delete(deleteUri, null, null)
                        if (rows == -1) { //事件删除失败
                            return
                        }
                    }
                    this.moveToNext()
                }
            }
        }
    }


    /**
     * 添加单条事件到日历
     *
     * @param bean 数据类型
     * @param isNextDay 今天是否要添加
     * @param site_sign 事件地点标识 有默认值可以不填
     * @param description 事件描述
     * @param reminderType  添加事件重复类型  ReminderType.TYPE_NUMBER 按次 如果是这个参数  需要传入number
     *                                   ReminderType.TYPE_EVER 永久  不需要传入number
     * @param number 如果是按次重复事件  需要传入这个参数 有默认值 2
     */
    fun addCalendar(
        context: Context, bean: CalendarDataBean, isNextDay: Boolean,
        site_sign: String = SITE_SIGN, description: String,
        reminderType: TypeStatus,
        number: Int = 2,
    ) {
        /*添加前先情况集合*/
        deleteCalendarEvent(context, site_sign)

        val mCalendar = Calendar.getInstance()
        /*是设置日历的时间，主要是让日历的年月日和当前同步*/
        mCalendar.timeInMillis = System.currentTimeMillis()
        /*这里时区需要设置一下，不然可能个别手机会有8个小时的时间差*/
        mCalendar.timeZone = TimeZone.getTimeZone("GMT+8")
        /*设置在几点提醒  设置的为几点*/
        mCalendar.set(Calendar.HOUR_OF_DAY, bean.mHour)
        /*设置在几分提醒  设置的为几分*/
        mCalendar.set(Calendar.MINUTE, bean.mMinute)
        mCalendar.set(Calendar.SECOND, 0)
        mCalendar.set(Calendar.MILLISECOND, 0)
        /*是否直接添加第二天事件  第二天事件直接日期+1*/
        if (isNextDay) {
            mCalendar.add(Calendar.DAY_OF_MONTH, 1)
            addCalendarEvent(
                context, bean.mTitle, mCalendar.timeInMillis, site_sign, description,
                reminderType, number - 1
            )
        } else {
            addCalendarEvent(
                context, bean.mTitle, mCalendar.timeInMillis, site_sign, description,
                reminderType, number
            )
        }
    }


    /**
     * 添加多条事件
     *
     * @param beanList 数据类型集合
     *
     * @param isNextDay 今天是否要添加
     *
     * @param site_sign 事件地点标识 有默认值可以不填
     *
     * @param description 事件描述
     *
     * @param reminderType  添加事件重复类型  ReminderType.TYPE_NUMBER 按次 如果是这个参数  需要传入number
     *                                   ReminderType.TYPE_EVER 永久  不需要传入number
     *  @param number 如果是按次重复事件  需要传入这个参数 有默认值 2
     *
     *  @param weekendReminder 周末是否提醒 默认提醒
     *
     *  @param openStartTime 开启提醒 开始时间
     *
     *  @param openEndTime 开启提醒 截止时间
     *
     *  @param isNoReminder 是否开启免打扰  默认不开启 不开启时 免打扰时间为 0 设置了 开启 免打扰时间必须设置
     *
     *  @param noStartTime 免打扰 开始时间
     *
     *  @param noEndTime 免打扰 截止时间
     */
    fun addCalendarList(
        context: Context, beanList: MutableList<CalendarDataBean>, isNextDay: Boolean,
        site_sign: String = SITE_SIGN, description: String,
        reminderType: TypeStatus,
        number: Int = 1,
        weekendReminder: Boolean = true,
        openStartTime: Long,
        openEndTime: Long,
        isNoReminder: Boolean = false,
        noStartTime: Long = 0L,
        noEndTime: Long = 0L
    ) {
        /*添加前先情况集合*/
//        deleteCalendarEvent(context, site_sign)

        beanList.forEach {
            val mCalendar = Calendar.getInstance()
            /*是设置日历的时间，主要是让日历的年月日和当前同步*/
            mCalendar.timeInMillis = System.currentTimeMillis()
            /*这里时区需要设置一下，不然可能个别手机会有8个小时的时间差*/
            mCalendar.timeZone = TimeZone.getTimeZone("GMT+8")
            /*设置在几点提醒  设置的为几点*/
            mCalendar.set(Calendar.HOUR_OF_DAY, it.mHour)
            /*设置在几分提醒  设置的为几分*/
            mCalendar.set(Calendar.MINUTE, it.mMinute)
            mCalendar.set(Calendar.SECOND, 0)
            mCalendar.set(Calendar.MILLISECOND, 0)

            //要添加的系统时间
            val selectTime = mCalendar.timeInMillis

            if (isNoReminder) { /**是否开启免打扰时间  开启了*/

                if (noStartTime == 0L || noEndTime == 0L) {
                    Log.e("AddCalender", "请填写免打扰时间段")
                    throw IllegalAccessException("======请填写免打扰时间段======")
                }

                /**设置的提醒时间  开启了免打扰时间  不包含免打扰时间 */
                if (selectTime in openStartTime until noStartTime || selectTime in noEndTime + 1..openEndTime) {
                    /*是否直接添加第二天事件  第二天事件直接日期+1*/
                    if (isNextDay) {
                        mCalendar.add(Calendar.DAY_OF_MONTH, 1)
                        addCalendarEvent(
                            context, it.mTitle, mCalendar.timeInMillis, site_sign, description,
                            reminderType, number - 1, weekendReminder
                        )
                    } else {
                        //当前系统时间
                        var systemTime = System.currentTimeMillis()

                        if (systemTime > selectTime) {
                            mCalendar.add(Calendar.DAY_OF_MONTH, 1)
                            addCalendarEvent(
                                context, it.mTitle, mCalendar.timeInMillis, site_sign, description,
                                reminderType, number - 1, weekendReminder
                            )
                        } else {
                            addCalendarEvent(
                                context, it.mTitle, selectTime, site_sign, description,
                                reminderType, number, weekendReminder
                            )
                        }
                    }
                }
            } else { /**设置的提醒时间 没有开启免打扰时间*/
                if (selectTime in openStartTime..openEndTime) {
                    /*是否直接添加第二天事件  第二天事件直接日期+1*/
                    if (isNextDay) {
                        mCalendar.add(Calendar.DAY_OF_MONTH, 1)
                        addCalendarEvent(
                            context, it.mTitle, selectTime, site_sign, description,
                            reminderType, number - 1, weekendReminder
                        )
                    } else {

                        //当前系统时间
                        var systemTime = System.currentTimeMillis()

                        if (systemTime > selectTime) {
                            mCalendar.add(Calendar.DAY_OF_MONTH, 1)
                            addCalendarEvent(
                                context, it.mTitle, mCalendar.timeInMillis, site_sign, description,
                                reminderType, number - 1, weekendReminder
                            )
                        } else {
                            addCalendarEvent(
                                context, it.mTitle, selectTime, site_sign, description,
                                reminderType, number, weekendReminder
                            )
                        }
                    }
                }
            }
        }
    }

    /**
     * 通过起始时间和截止时间来添加 区间事件段
     *
     * @param startTime 事件集合的起始时间
     * @param endTime 事件集合的截止时间
     * @param timeInterval 事件的间隔时间
     * @param nextTime 喝水之后多久多久内不提醒 配合 nextTimeType 字段用
     * @param description 事件备注描述
     * @param list 事件集合 --时间对应的 标题名称
     * @param site_sign 事件标记 有默认值  可以不填
     * @param nextTimeType 是否喝水了  喝水后 执行时间间隔内不提醒 配合 nextTime 一起用 默认值 false
     *                      为false 时 nextTime 不生效
     * @param nextDay 是否添加当天的 有默认值 false
     * @param reminderType 添加事件重复类型  ReminderType.TYPE_NUMBER 按次 如果是这个参数  需要传入number
     *                                   ReminderType.TYPE_EVER 永久  不需要传入number
     * @param number 如果是按次重复事件  需要传入这个参数 有默认值 2
     */
    fun addCalendarTimeScope(
        context: Context,
        startTime: Long, endTime: Long, timeInterval: Long, nextTime: Long,
        description: String,
        list: MutableList<CalendarDataBean>,
        site_sign: String = SITE_SIGN,
        nextTimeType: Boolean = false, nextDay: Boolean = false,
        reminderType: TypeStatus, number: Int = 2,
    ) {
        //提醒时间 从起始时间开始计入
        var reminderTime = startTime

        val nextDayTime = Calendar.getInstance()

        //循环添加
        while (reminderTime <= endTime) {

            nextDayTime.timeInMillis = reminderTime
            nextDayTime.add(Calendar.DAY_OF_MONTH, 1)

            /*12 - 14 点不提醒   如果 要灵活使用这个时间段  就在前面 在家一个Boolean值 让外部传入控制 是否开启
            * (isOpen || reminderTime <= getTimeInMillis(12, 0) || reminderTime >= getTimeInMillis(14, 0))
            *  */
            if (reminderTime <= getTimeInMillis(12, 0) || reminderTime >= getTimeInMillis(14, 0)) {

                /*筛选标题*/
                val title = getTitle(reminderTime, list)

                /*是否添加今天的事件*/
                if (nextDay) {
                    //添加事件
                    addCalendarEvent(
                        context, title,
                        nextDayTime.timeInMillis,
                        site_sign,
                        description,
                        reminderType,
                        number - 1
                    )
                } else {
                    var time = System.currentTimeMillis()
                    if (nextTimeType) {
                        time += nextTime
                    }
                    if (reminderTime < time) {
                        addCalendarEvent(
                            context,
                            title,
                            nextDayTime.timeInMillis,
                            site_sign,
                            description,
                            reminderType,
                            number - 1
                        )
                    } else {
                        /*添加正常事件*/
                        addCalendarEvent(
                            context,
                            title,
                            reminderTime,
                            site_sign,
                            description,
                            reminderType,
                            number
                        )
                    }
                }
            }
            reminderTime += timeInterval
        }
    }

    /**
     * 获取事件的标题标题
     *
     * @param time 事件的时间
     * @param list 外部传入的集合 时间+该时间段对应的title
     */
    private fun getTitle(time: Long, list: MutableList<CalendarDataBean>): String {

        var title = "默认标题"
        list.forEach { item ->
            if (time == getTimeInMillis(item.mHour, item.mMinute)) {
                title = item.mTitle
            }
        }
        return title
    }

    /**
     * 转化成时间戳
     */
    private fun getTimeInMillis(hour: Int, minute: Int): Long {
        val mCalendar = Calendar.getInstance()
        /*是设置日历的时间，主要是让日历的年月日和当前同步*/
        mCalendar.timeInMillis = System.currentTimeMillis()
        /*这里时区需要设置一下，不然可能个别手机会有8个小时的时间差*/
        mCalendar.timeZone = TimeZone.getTimeZone("GMT+8")
        /*设置在几点提醒  设置的为几点*/
        mCalendar.set(Calendar.HOUR_OF_DAY, hour)
        /*设置在几分提醒  设置的为几分*/
        mCalendar.set(Calendar.MINUTE, minute)
        mCalendar.set(Calendar.SECOND, 0)
        mCalendar.set(Calendar.MILLISECOND, 0)
        return mCalendar.timeInMillis
    }
}